<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  vue的脚手架 vue-cli

  1. npm install -g @vue/cli
  2. 安装成功 vue -V 出现版本号
  3. 创建项目 vue create 项目名称 创建件的项目搭建好完整的webpack

  Manually select features 自定义项目

  (*) Choose Vue version 版本
  (*) Babel es6--es5
  ( ) TypeScript 是否使用 ts
  ( ) Progressive Web App (PWA) Support 是否支持pwa
  (*) Router 是否使用 Router
  (*) Vuex 是否使用 vuex
  (*) CSS Pre-processors 是否使用 预处理 less sass stylus
  >(*) Linter / Formatter 是否使用 eslint 语法检测
  ( ) Unit Testing 是否使用 单元测试
  ( ) E2E Testing 是否使用 E2E元测试

  ? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
  > 2.x
  3.x

  ?Use history mode for router? router是否是history
  (Requires proper server setup for index fallback in production) (Y/n) n

  css预处理 语言
  ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow ke
  ys)
  Sass/SCSS (with dart-sass)
  Sass/SCSS (with node-sass)
  >Less
  Stylus

  eslint 语法检测
  ? Pick a linter / formatter config: (Use arrow keys)
  > ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier

  ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
        >(*) Lint on save
        ( ) Lint and fix on commit

        接着，选择在什么时间进行检测，这里有两个选项（多选）：
        Lint on save：保存时检测
        Lint and fix on commit：提交时检测

        ? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
        > In dedicated config files
        In package.json

        接着，选择在什么位置保存配置文件，这里有两个选项（单选）：
        In dedicated config files：独立保存为 config 文件
        In package.json：全部保存在 package.json 文件


        ? Save this as a preset for future projects? (y/N) n
        最后，选择是否保存本次配置以便于下次使用，这里有两个选项（y/N）：
        y：保存配置
        N：不保存配置

        下一步 打开创建的项目
        cd vuedemo

        启动 创建的项目(开发环境)
        yarn serve/ npm run serve

        打包项目 (生产环境)
        yarn build / npm run build

        public
        |--index.html 打包入口的html文件
        src
        |--api ajax请求及封装文件
        |--assets 静态资源文件
        |--components 业务组件
        |--router 路由文件夹
        |--store vuex文件夹
        |--views/pages vue的页面
        |--App.vue vue入口页面
        |--main.js 入口的js文件
        .browserslistrc 配置文件 浏览器兼容
        .eslintrc.js eslint 配置文件
        babel.config.js 配置文件 es6--es5
        .gitgnore .git 配置文件
        package.json npm包管理器的清单
        vue.config.js 配置 相当于 webpack.config.js


        每个XXX.vue的页面都是一个“组件”
        <template>
          <div class="XX">
          </div>
        </template> 视图
        <script>
          export default {
            data() {
              return {
                num: 100
              }
            }
          }
        </script> js

        使用less编译
        <style lang="less"></style> css

        创建组件：
        串式命名： my-name-apple
        大驼峰命名： MyNameApple


        组件：类组件 函数组件
        组件----类组件（vue的组件基本上都是类组件）
        类组件可以变成函数组件
        <template functional>
        </template>
        只能使用 template+style

        组价：局部组件 全局组件

        局部组件：
        1. 创建一个组件（components 文件夹） 大驼峰 OnePage.vue

        2. 在某个路由组件中使用（切页面的）
        // 导入组件 @--->src目录
        import OnePage from '@/components/OnePage.vue'
        // 导入组件
        import OnePage from '../components/OnePage.vue'

        export default{
        components: {//挂载
        OnePage
        }
        }


        template使用
        <!-- 使用组件 串式 -->
        <one-page></one-page>

        全局组件
        1. 创建一个组件（components 文件夹） 大驼峰 TwoPage.vue

        2. 在main.js 中，导入组件
        import TwoPage from "./components/TwoPage.vue"

        3. Vue.component("TwoPage",TwoPage) 声明成为全局组件
        Vue.component(组件名称,组件)

        4.使用组件
        直接在组件中使用
        <two-page></two-page>


        组件通信****
        1. 父组件向子组件传递数据
        父组件自定义属性
        <one-page :numMsg="num" str="hello"></one-page>

        子组件通过 props 接收（子组的props接收方式，有两种，数组(不进行格式校验)，对象（进行格式校验））
        props:["numMsg","str"]

        props: {
        // 基础类型检测, null意味着任何类型都行
        propA: Number,
        // 多种类型
        propB: [String, Number],
        // 必传且是String
        propC: {
        type: String,
        required: true
        },
        // 数字有默认值
        propD: {
        type: Number,
        default: 101
        },
        // 数组、默认值是一个工厂函数返回对象
        propE: {
        type: Object,
        default: function() {
        console.log("propE default invoked.");
        return { message: "I am from propE." };
        }
        },
        // 自定义验证函数
        propF: {
        isValid（validator）: function(value) {
        return value > 100;
        }
        }
        }


        接收完成后，子组件可以直接使用，但是不允许修改（修改会报警告性错误）
        <h1>OnePage---{{ numMsg }}--{{ str }}</h1>


        2.子组件---》父组件传递数据（发布订阅的方式）
        父子组件传递数据时，只能由父组件直接流向子组件，不能由子组件直接流向父组件。
        这样会防止从子组件意外改变父级组件的状态，从而导致你的应用的数据流向难以理解。

        1.父组件自定义一个事件（向事件池中添加方法）
        <three-page @myEvent="show"></three-page>
        export default{
        methods:{
        show(...args){
        console.log(args);
        }
        }
        }

        2.子组件，通过 $emit 来执行自定义事件 并且 将参数传递给父组件
        <button @click="send">点击按钮触发$emit</button>
        export default {
        data(){
        return {
        msg:"qqq"
        }
        },
        methods:{
        send(){
        this.$emit("myEvent",10,20,this.msg);
        }
        }
        }

        3.兄弟组件通信（父子，子父）任何组件的通信----发布订阅

        1.在main.js创建一个新的实例

        //创建一个全新的实例EventBus
        let EventBus=new Vue()
        //EventBus实例-》Vue.prototype（$emit,$on,$off）-》Object.prototype-》null
        //EventBus添加到Vue的原型上
        Vue.prototype.$bus=EventBus;

        2.创建两个兄弟组件
        BPage---》APage 传递参数

        BPage
        <button @click="send">发送数据</button>
        export default {
        methods:{
        send(){
        //$emit 执行事件池中的方法，并且传递参数
        this.$bus.$emit("AAA",100,200)
        }
        }
        }

        Apage
        created(){
        //$on 向事件池中添加自定义事件
        this.$bus.$on("AAA",this.showa)
        },
        methods:{
        showa(...args){//接收参数
        console.log(args);
        }
        }

        4.vue实例属性
        $parent 获取父元素的数据/方法
        $root 获取根组件的数据/方法
        $children 获取子元素的数据/方法(mounted钩子函数，要有下标）
        $refs 作用1：获取子组件的方法和数据/作用2：获取DOM元素
        作用1：获取子组件的方法和数据（组件标签）
        <a-page ref="apage"></a-page>
        mounted(){//必须在mounted 钩子里获取子组件,父子组件生命周期
        console.log(this.$refs.apage);
        }

        作用2：获取DOM元素（普通标签）
        <h1 ref="hone">1111</h1>
        mounted(){
        console.log(this.$refs.hone);
        }

        5.祖先后代通信
        祖先组件：
        provide(){//祖先组件传递数据,默认会失去响应式效果，
        //但是传递的是对象，对象里面的值不会失去响应式效果
        return{
        n:this.n,
        m:this.m,
        obj:this.obj
        }
        }

        后代组件：
        <h1>{{ n }}</h1>

        inject:["n","m","obj"],//后代组件接收参数

        6.vuex


        组件其他相关知识
        1. .native 子组件上添加事件（父组件），触发事件，没有.native无法触发
        无法在组件直接使用事件，需要加修饰符来实现 根元素上监听原生事件
        （把vue组件转化成一个普通的HTML标签，并且对普通的HTML标签是没有任何作用的）

        2. 实例方法

        1. $mount("#box")=====>手动挂载 el 可以替换原来的挂载
        2. $set(要修改的数据,属性名，属性值)/$set(要修改的数据,属性名，属性值)
        ====>任何时候添加对象属性，页面都会更新
        3. $destroy()====>销毁 destoryed/beforeDestroy
        4. $delete(vm.jsona,属性名)====>任何时候删除对象属性,页面都会更新
        5. $forceUpdate() 强制更新
        6. $nextTick() 相当于Promise.then template--》虚拟DOM ---》真实DOM
        template--》虚拟DOM ---》真实DOM，等整个流程都完毕，最后执行

        3.动态组件 component + is

        <button @click="flag='APage'">AA</button>
        <button @click="flag='BPage'">BB</button>

        <component :is="flag"></component>

        data(){
        return {
        flag:"APage"
        }
        }

        4.******插槽
        默认组件标签中添加内容，不会显示，会被组件内容覆盖，插槽：就是让内容展示

        普通插槽 使用<slot></slot>
        <two-page>
          <h3>哈哈哈</h3>
          <h4>3333</h4>
        </two-page>
        -----

        <template>
          <div>
            <slot></slot>
            <h1>TwoPage</h1>
            <slot></slot>
          </div>
        </template>

        具名插槽

        方法1：
        <two-page @click.native="show">
          <template slot="header">
            <h3>哈哈哈</h3>
          </template>
          <template slot="footer">
            <h4>3333</h4>
          </template>
        </two-page>
        ----
        <template>
          <div>
            <slot name="header"></slot>
            <h1>TwoPage</h1>
            <slot name="footer"></slot>
          </div>
        </template>

        方法2****： 使用指令 v-slot 简写 #
        #default 默认，可以不写name

        <two-page @click.native="show">
          <template #default>
            <h3>11111</h3>
          </template>
          <template #header>
            <h3>哈哈哈</h3>
          </template>
          <template v-slot:footer>
            <h4>3333</h4>
          </template>
        </two-page>
        ----
        <template>
          <div>
            <slot name="header"></slot>
            <h1>
              TwoPage
              <slot></slot>
            </h1>
            <slot name="footer"></slot>
          </div>
        </template>

        3.***作用域插槽

        方法1：
        可以不写slot="footer"+name="footer"
        <two-page>
          <template slot="footer" slot-scope="options">
            <h4>{{ options.arrdata }}</h4>
          </template>
        </two-page>
        ---
        <template>
          <div>
            <h1>
              TwoPage
            </h1>
            <slot name="footer" :arrdata="arr"></slot>
          </div>//自定义属性
        </template>


        data(){
        return {
        arr:["apple","banana","pear"]
        }
        }


        方法2****：
        不能取默认 default
        <two-page @click.native="show">
          <template #footer="options"> //使用v-slot指令接收参数
            <h4>{{ options.arrdata }}</h4>
          </template>
        </two-page>
        ---
        <template>
          <div>
            <h1>
              TwoPage
            </h1>
            <slot name="footer" :arrdata="arr"></slot>
          </div>//自定义属性
        </template>


        data(){
        return {
        arr:["apple","banana","pear"]
        }
        }





        ---------------------------------
        1. 样式私有化
        默认 style填写样式，是全局样式
        添加 scoped 的属性，就会变成私有样式

        <style scoped>
          h1 {
            color: red;
            background-color: yellow;
          }
        </style>

        原理，是给标签，添加一个唯一属性，样式设置的时候也添加了唯一属性
        <div data-v-1c62cf7b>
          <h1 data-v-1c62cf7b>TwoPage</h1>
        </div>

        h1[data-v-1c62cf7b] {
        color: red;
        background-color: yellow;
        }



















</body>

</html>